#include <iostream>
#include <algorithm>
#include <queue>

using namespace std;

#define MAXSIZE 7 

int number; 
int flag; 

struct process
{
    string pid;        
    int pos;            
    double come_time;  
    double run_time;   
    double begin_time; 
    double over_time;  
    double round_time; 
    double priority;
    double avg_time;   
}
        pc[MAXSIZE];         

bool CmpByComeTime(process p1, process p2) 
{
    return p1.come_time < p2.come_time;
}

bool CmpByPid(process p1, process p2) 
{
    return p1.pid < p2.pid;
}

bool CmpByRunTime(process p1, process p2) 
{
    return p1.run_time == p2.run_time ? p1.come_time < p2.come_time : p1.run_time < p2.run_time;
}

bool ComByPriority(process p1 ,process p2){
    return p1.priority == p2.priority ? p1.come_time < p2.come_time : p1.priority > p2.priority;
}

void get_beginAndOver_time1() 
{
    for (int i = 0; i < number; i++)
    {
        if (i == 0)
        {
            pc[i].begin_time = pc[i].come_time; 
        }
        else
        {
            if(pc[i].come_time<=pc[i-1].over_time){
            pc[i].begin_time = pc[i - 1].over_time; 
            }else{
                pc[i].begin_time = pc[i].come_time;
            }
        }
        pc[i].over_time = pc[i].begin_time + pc[i].run_time; 
    }
}

void get_beginAndOver_time() 
{
    for (int i = 0; i < number; i++)
    {
        if (i == 0)
        {
            pc[i].begin_time = pc[i].come_time; 
            pc[i].over_time = pc[i].begin_time + pc[i].run_time;
        }
        else if(flag==2||flag==3){
            process pool[7];
            int stacknum=0;
            for(int j=i;j<number;j++){
                if(pc[j].come_time<pc[i-1].over_time){
                    pool[stacknum]=pc[j];
                    stacknum= stacknum + 1;
                }
            }
            if(stacknum==0){
                pc[i].begin_time=pc[i].come_time;
                pc[i].over_time= pc[i].begin_time + pc[i].run_time;
            }
            else if(stacknum==1){
                pc[i].begin_time=pc[i-1].over_time;
                pc[i].over_time= pc[i].begin_time + pc[i].run_time;
            }
            else if(stacknum>1){
                if(flag==2){
                    int position=0;
                    sort(pool,pool+stacknum, CmpByRunTime);
                    for(int u=i;u<number;u++){
                        if(pc[u].pos==pool[0].pos){
                            position=u;
                            break;
                        }
                    }
                    pc[position]=pc[i];
                    pc[i]=pool[0];
                }else if(flag==3){
                    int position=0;
                    sort(pool,pool+stacknum, ComByPriority);
                    for(int u=i;u<number;u++){
                        if(pc[u].pos==pool[0].pos){
                            position=u;
                            break;
                        }
                    }
                    pc[position]=pc[i];
                    pc[i]=pool[0];
                }
                pc[i].begin_time=pc[i-1].over_time;
                pc[i].over_time = pc[i].begin_time + pc[i].run_time;
            }

        }

    }

}

void get_roundAndAvg_time() 
{
    for (int i = 0; i < number; ++i)
    {
        pc[i].round_time = pc[i].over_time - pc[i].come_time;     
        pc[i].avg_time = pc[i].round_time * 1.0 / pc[i].run_time; 
    }
}


void printResult() 
{
    cout << "The process execution sequence is:"; // << endl
    for (int i = 0; i < number; ++i)
    {
        /* code */
        cout << pc[i].pid << " ";
    }
    cout << endl;
    cout << "name"  << "arrival_time" << '\t' << " exexcute_time " <<" priority "
         << " start_time " << " end_time "  << "turnaround_time "
         << "WTAT" << '\t' << endl;
    sort(pc, pc + number, CmpByPid);
    double sum_round_time = 0.0;
    double avg_sum_round_time = 0.0; 
    double sum_avg_time = 0.0;
    double avg_sum_avg_time = 0.0; 
    for (int i = 0; i < number; ++i)
    {
        sum_round_time += pc[i].round_time;
        sum_avg_time += pc[i].avg_time;
        cout << pc[i].pid << '\t' << pc[i].come_time << '\t'
             << pc[i].run_time << '\t' <<pc[i].priority<< '\t' << pc[i].begin_time << '\t'
             << pc[i].over_time << '\t' << pc[i].round_time << '\t'
             << pc[i].avg_time << endl;
    }
    avg_sum_round_time = sum_round_time * 1.0 / number;
    avg_sum_avg_time = sum_avg_time * 1.0 / number;
    cout << "Average TAT is: " << avg_sum_round_time << endl
         << "Average WTAT is: " << avg_sum_avg_time << endl;
}

int main()
{
    cout << "Please input the number of processes";
    cin >> number;

    cout << endl;
    cout << "Input p_id arrival_time execute_time priority " << endl;
    for (int i = 0; i < number; i++)
    {
        cin >> pc[i].pid >> pc[i].come_time >> pc[i].run_time >> pc[i].priority;
        pc[i].pos=i;
    }

    cout << endl;
    flag=1;
    sort(pc, pc + number, CmpByComeTime);
    get_beginAndOver_time1();
    get_roundAndAvg_time();
    cout << " FCFS  RESULT :" << endl;
    printResult();

    cout << endl;
    flag=2;
    sort(pc, pc + number, CmpByComeTime);
    get_beginAndOver_time();
    get_roundAndAvg_time();
    cout << "SJF   RESULT :" << endl;
    printResult();

    cout << endl;
    flag=3;
    sort(pc, pc + number, CmpByComeTime);
    get_beginAndOver_time();
    get_roundAndAvg_time();
    cout << "PPS RESULT: " << endl;
    printResult();

    cout << endl;
    system("pause");
    return 0;
}
